home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / ole2book.zip / CHAP07.ZIP / CHAP07 / PATRON / PAGE.CPP < prev    next >
C/C++ Source or Header  |  1993-06-17  |  22KB  |  935 lines

  1. /*
  2.  * PAGE.CPP
  3.  * Modifications for Chapter 7
  4.  *
  5.  * Implementation of parts of the CPage class; those member functions
  6.  * dealing with mouse events are in PAGEMOUS.CPP
  7.  *
  8.  * Copyright (c)1993 Microsoft Corporation, All Rights Reserved
  9.  *
  10.  * Kraig Brockschmidt, Software Design Engineer
  11.  * Microsoft Systems Developer Relations
  12.  *
  13.  * Internet  :  kraigb@microsoft.com
  14.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  15.  */
  16.  
  17.  
  18. #include "patron.h"
  19.  
  20.  
  21. /*
  22.  * CPage::CPage
  23.  * CPage::~CPage
  24.  *
  25.  * Constructor Parameters:
  26.  *  dwID            DWORD identifier for this page.
  27.  *  hWnd            HWND of the pages window (for repaints, etc).
  28.  *  pPG             LPCPages to the Pages window.
  29.  */
  30.  
  31. //CHAPTER7MOD
  32. CPage::CPage(DWORD dwID, HWND hWnd, LPCPages pPG)
  33. //End CHAPTER7MOD
  34.     {
  35.     m_dwID     =dwID;
  36.     m_pIStorage=NULL;
  37.  
  38.     //CHAPTER7MOD
  39.     m_cOpens=0;
  40.     m_hWnd=hWnd;
  41.     m_pPG=pPG;
  42.  
  43.     m_dwIDNext      =0;
  44.     m_cTenants      =0;
  45.     m_hWndTenantList=NULL;
  46.     m_iTenantCur    =0xFFFF;    //Tenants are zero indexed.
  47.     m_pTenantCur    =NULL;
  48.  
  49.     m_uHTCode=HTNOWHERE;
  50.     m_uSizingFlags=0;
  51.     m_fTracking=FALSE;
  52.     m_hDC=NULL;
  53.     //End CHAPTER7MOD
  54.  
  55.     return;
  56.     }
  57.  
  58.  
  59. CPage::~CPage(void)
  60.     {
  61.     m_hWnd=NULL;
  62.     Close(FALSE);
  63.     return;
  64.     }
  65.  
  66.  
  67.  
  68. /*
  69.  * CPage::GetID
  70.  *
  71.  * Return Value:
  72.  *  DWORD           dwID field in this page.  This function is only here
  73.  *                  to avoid hiding inline implementations in pages.h
  74.  */
  75.  
  76. DWORD CPage::GetID(void)
  77.     {
  78.     return m_dwID;
  79.     }
  80.  
  81.  
  82.  
  83.  
  84.  
  85. /*
  86.  * CPage::FOpen
  87.  *
  88.  * Purpose:
  89.  *  Retrieves the IStorage associated with this page.  The IStorage is
  90.  *  owned by the page and thus the page always holds a reference count.
  91.  *  The caller should call ::Close or delete this page to match this open.
  92.  *
  93.  *  This function may be called multiple times resulting in additional
  94.  *  reference counts on the storage each of which must be matched with
  95.  *  a call to ::Close.  The last ::Close can be done through delete.
  96.  *
  97.  * Parameters:
  98.  *  pIStorage       LPSTORAGE in which this page lives.
  99.  *
  100.  * Return Value:
  101.  *  BOOL            TRUE if opening succeeds, FALSE otherwise.
  102.  */
  103.  
  104. BOOL CPage::FOpen(LPSTORAGE pIStorage)
  105.     {
  106.     //CHPATER7MOD
  107.     HRESULT         hr=NOERROR;
  108.     LPSTREAM        pIStream;
  109.     DWORD           dwMode;
  110.     char            szTemp[32];
  111.     BOOL            fNew;
  112.     BOOL            fCreated=FALSE;
  113.     TENANTLIST      tl;
  114.     LPTENANTINFO    pti;
  115.     ULONG           cb;
  116.     LPMALLOC        pIMalloc;
  117.     UINT            i;
  118.     LPTENANT        pTenant;
  119.  
  120.     fNew=(NULL==m_pIStorage);
  121.  
  122.     if (!fNew)
  123.         {
  124.         m_cOpens++;
  125.         m_pIStorage->AddRef();
  126.         return TRUE;
  127.         }
  128.  
  129.     if (NULL==pIStorage)
  130.         return FALSE;
  131.  
  132.     /*
  133.      * Attempt to open the storage under this ID.  If there is none, then
  134.      * create it.  In either case we end up with an IStorage that we
  135.      * either save in pPage or release.
  136.      */
  137.  
  138.     GetStorageName(szTemp);
  139.     dwMode=STGM_TRANSACTED | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  140.  
  141.     hr=pIStorage->OpenStorage(szTemp, NULL, dwMode, NULL, 0, &m_pIStorage);
  142.  
  143.     if (FAILED(hr))
  144.         {
  145.         hr=pIStorage->CreateStorage(szTemp, dwMode, 0, 0, &m_pIStorage);
  146.         fCreated=TRUE;
  147.         }
  148.  
  149.     if (FAILED(hr))
  150.         return FALSE;
  151.  
  152.     m_cOpens++;
  153.  
  154.     if (NULL==m_hWndTenantList)
  155.         {
  156.         /*
  157.          * The first time we open this page, create the hidden listbox
  158.          * we'll use to track tenants.  We give it the owner-draw style
  159.          * so we can just store pointers in it.
  160.          */
  161.         m_hWndTenantList=CreateWindow("listbox", "Tenant List"
  162.             , WS_POPUP | LBS_OWNERDRAWFIXED, 0, 0, 100, 100
  163.             , HWND_DESKTOP, NULL, m_pPG->m_hInst, NULL);
  164.  
  165.         if (NULL==m_hWndTenantList)
  166.             return FALSE;
  167.         }
  168.  
  169.  
  170.     //If this is brand-new, we're done.
  171.     if (fCreated)
  172.         return TRUE;
  173.  
  174.  
  175.     /*
  176.      * Now open the stream we saved in ::Close and load all the
  177.      * tenants listed in there.  If there are none, then we don't
  178.      * have to load squat.
  179.      */
  180.  
  181.     hr=m_pIStorage->OpenStream(SZSTREAMTENANTLIST, NULL, STGM_DIRECT
  182.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  183.  
  184.     if (FAILED(hr))
  185.         return FALSE;
  186.  
  187.     if (SUCCEEDED(CoGetMalloc(MEMCTX_SHARED, &pIMalloc)))
  188.         {
  189.         pIStream->Read((LPVOID)&tl, sizeof(tl), NULL);
  190.         m_cTenants=tl.cTenants;
  191.         m_dwIDNext=tl.dwIDNext;
  192.         m_iTenantCur=0;
  193.  
  194.         cb=tl.cTenants*sizeof(TENANTINFO);
  195.  
  196.         if (0!=cb)
  197.             {
  198.             pti=(LPTENANTINFO)pIMalloc->Alloc(cb);
  199.  
  200.             if (NULL!=pti)
  201.                 {
  202.                 pIStream->Read((LPVOID)pti, cb, NULL);
  203.  
  204.                 for (i=0; i < m_cTenants; i++)
  205.                     {
  206.                     if (FTenantAdd(-1, (pti+i)->dwID, &pTenant))
  207.                         pTenant->FLoad(m_pIStorage, &(pti+i)->fe, &(pti+i)->rcl);
  208.                     }
  209.  
  210.                 pIMalloc->Free((LPVOID)pti);
  211.                 }
  212.             }
  213.  
  214.         pIMalloc->Release();
  215.         }
  216.  
  217.     pIStream->Release();
  218.  
  219.     //Get and select the first tenant
  220.     if (FTenantGet(0, &m_pTenantCur, FALSE))
  221.         m_pTenantCur->Select(TRUE);
  222.  
  223.     return TRUE;
  224.     //End CHAPTER7MOD
  225.     }
  226.  
  227.  
  228.  
  229.  
  230.  
  231. /*
  232.  * CPage::Close
  233.  *
  234.  * Purpose:
  235.  *  Possibly commits the storage, then releases it reversing the
  236.  *  reference count from FOpen.
  237.  *
  238.  * Parameters:
  239.  *  fCommit         BOOL indicating if we're to commit.
  240.  *
  241.  * Return Value:
  242.  *  None
  243.  */
  244.  
  245. void CPage::Close(BOOL fCommit)
  246.     {
  247.     if (NULL==m_pIStorage)
  248.         return;
  249.  
  250.     if (fCommit)
  251.         Update();
  252.  
  253.     //CHAPTER7MOD
  254.     m_pIStorage->Release();
  255.  
  256.     //If this was the last close, make all tenants loaded->passive
  257.     if (0==--m_cOpens)
  258.         {
  259.         UINT        i;
  260.         LPTENANT    pTenant;
  261.  
  262.         m_pIStorage=NULL;
  263.  
  264.         for (i=0; i < m_cTenants; i++)
  265.             {
  266.             if (FTenantGet(i, &pTenant, FALSE))
  267.                 {
  268.                 if (NULL!=m_hWnd)
  269.                     {
  270.                     //FOpen may select again, so this repaints.
  271.                     pTenant->Select(FALSE);
  272.                     }
  273.  
  274.                 pTenant->Close(FALSE);
  275.                 delete pTenant;
  276.                 }
  277.             }
  278.  
  279.         DestroyWindow(m_hWndTenantList);
  280.         m_hWndTenantList=NULL;
  281.         }
  282.     //End CHAPTER7MOD
  283.  
  284.     return;
  285.     }
  286.  
  287.  
  288.  
  289.  
  290. /*
  291.  * CPage::Update
  292.  *
  293.  * Purpose:
  294.  *  Forces a common on the page if it's open.
  295.  *
  296.  * Parameters:
  297.  *  None
  298.  *
  299.  * Return Value:
  300.  *  BOOL            TRUE if there are any open objects on this page,
  301.  *                  that is, we should remain open.
  302.  */
  303.  
  304. BOOL CPage::Update(void)
  305.     {
  306.     //CHAPTER7MOD
  307.     BOOL            fOpen=FALSE;
  308.     UINT            i;
  309.     LPTENANT        pTenant;
  310.     HRESULT         hr;
  311.     LPSTREAM        pIStream;
  312.     TENANTLIST      tl;
  313.     LPTENANTINFO    pti;
  314.     ULONG           cb;
  315.     LPMALLOC        pIMalloc;
  316.  
  317.     //Walk the list of objects and update them all as well.
  318.     for (i=0; i < m_cTenants; i++)
  319.         {
  320.         if (FTenantGet(i, &pTenant, FALSE))
  321.             fOpen |= pTenant->Update();
  322.         }
  323.  
  324.     //Now write our own stream containing the tenant list.
  325.     hr=m_pIStorage->CreateStream(SZSTREAMTENANTLIST, STGM_CREATE | STGM_WRITE
  326.         | STGM_DIRECT | STGM_SHARE_EXCLUSIVE, 0, 0, &pIStream);
  327.  
  328.     if (FAILED(hr))
  329.         return fOpen;
  330.  
  331.     if (SUCCEEDED(CoGetMalloc(MEMCTX_SHARED, &pIMalloc)))
  332.         {
  333.         tl.cTenants=m_cTenants;
  334.         tl.dwIDNext=m_dwIDNext;
  335.  
  336.         pIStream->Write((LPVOID)&tl, sizeof(TENANTLIST), &cb);
  337.  
  338.         cb=m_cTenants*sizeof(TENANTINFO);
  339.         pti=(LPTENANTINFO)pIMalloc->Alloc(cb);
  340.  
  341.         if (NULL!=pti)
  342.             {
  343.             for (i=0; i < m_cTenants; i++)
  344.                 {
  345.                 FTenantGet(i, &pTenant, FALSE);
  346.                 (pti+i)->dwID=pTenant->GetID();
  347.                 pTenant->RectGet(&(pti+i)->rcl, FALSE);
  348.                 pTenant->FormatEtcGet(&(pti+i)->fe, FALSE);
  349.                 }
  350.  
  351.             pIStream->Write((LPVOID)pti, cb, &cb);
  352.             pIMalloc->Free((LPVOID)pti);
  353.             }
  354.  
  355.         pIMalloc->Release();
  356.         }
  357.  
  358.     pIStream->Release();
  359.  
  360.     //Now commit the whole mess and we're done
  361.     if (NULL!=m_pIStorage)
  362.         m_pIStorage->Commit(STGC_ONLYIFCURRENT);
  363.  
  364.     //End CHAPTER7MOD
  365.     return fOpen;
  366.     }
  367.  
  368.  
  369.  
  370.  
  371.  
  372. /*
  373.  * CPage::Destroy
  374.  *
  375.  * Purpose:
  376.  *  Removes this page from the given storage.  The caller should
  377.  *  eventually delete this Page object to free the storage.
  378.  *
  379.  * Parameters:
  380.  *  pIStorage       LPSTORAGE contianing this page on which to call
  381.  *                  ::DestroyElement
  382.  *
  383.  * Return Value:
  384.  *  None
  385.  */
  386.  
  387. void CPage::Destroy(LPSTORAGE pIStorage)
  388.     {
  389.     char        szTemp[32];
  390.  
  391.     if (NULL!=pIStorage)
  392.         {
  393.         if (NULL!=m_pIStorage)
  394.             m_pIStorage->Release();
  395.  
  396.         GetStorageName(szTemp);
  397.         pIStorage->DestroyElement(szTemp);
  398.  
  399.         m_pIStorage=NULL;
  400.         }
  401.  
  402.     return;
  403.     }
  404.  
  405.  
  406.  
  407.  
  408. //CHAPTER7MOD
  409.  
  410. /*
  411.  * CPage::GetStorageName
  412.  *
  413.  * Parameters:
  414.  *  pszName         LPSTR to a buffer in which to store the storage name
  415.  *                  for this page.
  416.  *
  417.  * Return Value:
  418.  *  UINT            Number of characters stored.
  419.  */
  420.  
  421. UINT CPage::GetStorageName(LPSTR pszName)
  422.     {
  423.     return wsprintf(pszName, "Page %lu", m_dwID);
  424.     }
  425.  
  426.  
  427.  
  428.  
  429. /*
  430.  * CPage::Draw
  431.  *
  432.  * Purpose:
  433.  *  Draws the objects on this page to the given hDC.
  434.  *
  435.  * Parameters:
  436.  *  hDC             HDC on which to draw.
  437.  *  xOff, yOff      int offsets for the page.
  438.  *  fNoColor        BOOL indicating a black & white screen rendering.
  439.  *  fPrinter        BOOL indicating hDC is on the printer.
  440.  *
  441.  * Return Value:
  442.  *  None
  443.  */
  444.  
  445. void CPage::Draw(HDC hDC, int xOff, int yOff, BOOL fNoColor, BOOL fPrinter)
  446.     {
  447.     int                 i;
  448.     LPTENANT            pTenant;
  449.     HDC                 hIC=NULL;
  450.     DVTARGETDEVICE FAR *ptd=NULL;
  451.  
  452.     /*
  453.      * This local structure eliminates having to allocate the
  454.      * DVTARGETDEVICE structure separately.  We can just stuff its
  455.      * fields with offsets to the DEVICECONFIG structure and the
  456.      * characters arrays.
  457.      */
  458.     struct
  459.         {
  460.         DVTARGETDEVICE  td;
  461.         DEVICECONFIG    dc;
  462.         } dev;
  463.  
  464.  
  465.     /*
  466.      * If printing, tell the tenant to forget the borders.  Otherwise
  467.      * we leave xOff and yOff the same to account for scrolling.
  468.      */
  469.     if (fPrinter)
  470.         {
  471.         xOff=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  472.         yOff=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  473.  
  474.         /*
  475.          * Create a DVTARGETDEVICE structure.  If this fails, we just
  476.          * pass ptd to CTenant::Draw, which is acceptable.
  477.          */
  478.         if (m_pPG->DevReadConfig(&dev.dc, &hIC))
  479.             {
  480.             WORD    cb=sizeof(DVTARGETDEVICE);
  481.  
  482.             dev.td.tdSize=cb;
  483.             dev.td.tdExtDevmodeOffset=cb;
  484.             dev.td.tdDriverNameOffset=cb+sizeof(DEVMODE);
  485.             dev.td.tdDeviceNameOffset=cb+sizeof(DEVMODE)+CCHDEVICENAME;
  486.             dev.td.tdPortNameOffset  =cb+sizeof(DEVMODE)+(CCHDEVICENAME*2);
  487.  
  488.             ptd=&dev.td;
  489.             }
  490.         }
  491.  
  492.     for (i=(int)m_cTenants-1; i >=0; i--)
  493.         {
  494.         if (FTenantGet(i, &pTenant, FALSE))
  495.             {
  496.             RECT        rc, rcWin;
  497.             RECTL       rcl;
  498.  
  499.             //Paint this tenant only if visible.
  500.             pTenant->RectGet(&rcl, TRUE);
  501.             RECTFROMRECTL(rc, rcl);
  502.             OffsetRect(&rc, -(int)m_pPG->m_xPos, -(int)m_pPG->m_yPos);
  503.             GetClientRect(m_hWnd, &rcWin);
  504.  
  505.             if (IntersectRect(&rc, &rc, &rcWin))
  506.                 pTenant->Draw(hDC, ptd, hIC, xOff, yOff, fNoColor, fPrinter);
  507.             }
  508.         }
  509.  
  510.     if (NULL!=hIC)
  511.         DeleteDC(hIC);
  512.  
  513.     return;
  514.     }
  515.  
  516.  
  517.  
  518.  
  519.  
  520.  
  521. /*
  522.  * CPage::TenantCreate
  523.  *
  524.  * Purpose:
  525.  *  Creates a new tenant of a specific type.
  526.  *
  527.  * Parameters:
  528.  *  tType           TENANTTYPE to create.
  529.  *  pv              LPVOID providing information for the new object creation.
  530.  *  pFE             LPFORMATETC describing how we want this rendered.
  531.  *  ppo             LPPATRONOBJECT with placement data.
  532.  *  dwData          DWORD extra data to pass to the tenant.
  533.  *
  534.  * Return Value:
  535.  *  None
  536.  */
  537.  
  538. BOOL CPage::TenantCreate(TENANTTYPE tType, LPVOID pv, LPFORMATETC pFE
  539.     , LPPATRONOBJECT ppo, DWORD dwData)
  540.     {
  541.     LPTENANT    pTenant;
  542.     UINT        uRet;
  543.     int         x, y;
  544.     int         h, v;
  545.     POINTL      ptl;
  546.     SIZEL       szl;
  547.     RECTL       rcl;
  548.     RECT        rc;
  549.  
  550.     //New tenants go at the top of the pile, so zero index to FTenantAdd.
  551.     if (!FTenantAdd(0, m_dwIDNext, &pTenant))
  552.         return FALSE;
  553.  
  554.     uRet=pTenant->UCreate(tType, pv, pFE, &ptl, &szl, m_pIStorage, ppo, dwData);
  555.  
  556.     if (UCREATE_FAILED==uRet)
  557.         {
  558.         //Reverse UCreate AND FTenantAdd
  559.         SendMessage(m_hWndTenantList, LB_DELETESTRING, 0, 0L);
  560.         pTenant->Destroy(m_pIStorage);
  561.  
  562.         delete pTenant;
  563.         return FALSE;
  564.         }
  565.  
  566.     m_dwIDNext++;
  567.     m_cTenants++;
  568.  
  569.     if (NULL!=m_pTenantCur)
  570.         m_pTenantCur->Select(FALSE);
  571.  
  572.     m_iTenantCur=0;             //First one in the list now.
  573.     m_pTenantCur=pTenant;
  574.  
  575.     //Tell the tenant where it lives, default is at (0,0) in print area
  576.     x=LOMETRIC_BORDER+m_pPG->m_xMarginLeft;
  577.     y=-LOMETRIC_BORDER-m_pPG->m_yMarginTop;
  578.  
  579.     h=x;
  580.     v=y;
  581.  
  582.     if (UCREATE_PLACEDOBJECT==uRet)
  583.         {
  584.         SetRect(&rc, 3*CXYHANDLE, 3*CXYHANDLE, 0, 0);
  585.         RectConvertMappings(&rc, NULL, FALSE);
  586.  
  587.         //Make sure the place point is on the page, otherwise go to (0,0)
  588.         if (((int)ptl.x > x) && ((int)ptl.x < x+(int)m_pPG->m_cx-rc.left))
  589.             x=(int)ptl.x;
  590.  
  591.         //m_pPG->m_cy is absolute
  592.         if (((int)ptl.y < y) && ((int)ptl.y > y-(int)m_pPG->m_cy-rc.top))
  593.             y=(int)ptl.y;
  594.         }
  595.  
  596.     //Bounds check the size of the object and fit to page as necessary.
  597.     if (x+(int)szl.cx > (int)(h+m_pPG->m_cx))
  598.         szl.cx=h+m_pPG->m_cx-x;
  599.  
  600.     //Remember that szl we get from UCreate is absolute
  601.     if (y-(int)szl.cy < (int)(v-m_pPG->m_cy))
  602.         szl.cy=-(int)(v-m_pPG->m_cy-y);
  603.  
  604.     SETRECTL(rcl, x, y, x+szl.cx, y-szl.cy);
  605.     m_pTenantCur->RectSet(&rcl, FALSE);
  606.  
  607.     //Force a repaint on this new guy
  608.     m_pTenantCur->Invalidate();
  609.     UpdateWindow(m_hWnd);
  610.  
  611.     m_pTenantCur->Select(TRUE);
  612.     return TRUE;
  613.     }
  614.  
  615.  
  616.  
  617.  
  618.  
  619.  
  620. /*
  621.  * CPage::TenantDestroy
  622.  *
  623.  * Purpose:
  624.  *  Destroys the currently selected tenant on this page.
  625.  *
  626.  * Parameters:
  627.  *  None
  628.  *
  629.  * Return Value:
  630.  *  None
  631.  */
  632.  
  633. BOOL CPage::TenantDestroy(void)
  634.     {
  635.     if (NULL==m_pTenantCur)
  636.         {
  637.         MessageBeep(0);
  638.         return FALSE;
  639.         }
  640.  
  641.     SendMessage(m_hWndTenantList, LB_DELETESTRING, m_iTenantCur, 0L);
  642.  
  643.     m_pTenantCur->Invalidate();
  644.     m_pTenantCur->Destroy(m_pIStorage);
  645.  
  646.     delete m_pTenantCur;
  647.     m_pTenantCur=NULL;
  648.  
  649.     //Update counts, etc., and select the next tenant in the list.
  650.     if (m_iTenantCur==m_cTenants-1)
  651.         m_iTenantCur--;
  652.  
  653.     if (0==--m_cTenants)
  654.         m_pTenantCur=NULL;
  655.     else
  656.         {
  657.         FTenantGet(m_iTenantCur, &m_pTenantCur, TRUE);
  658.         m_pTenantCur->Select(TRUE);
  659.         }
  660.  
  661.     UpdateWindow(m_hWnd);
  662.     return TRUE;
  663.     }
  664.  
  665.  
  666.  
  667.  
  668.  
  669. /*
  670.  * CPage::TenantClip
  671.  *
  672.  * Purpose:
  673.  *  Copies or cuts the currently selected tenant to the clipoard.
  674.  *
  675.  * Parameters:
  676.  *  fCut            BOOL TRUE to cut the object, FALSE to copy.
  677.  *
  678.  * Return Value:
  679.  *  BOOL            TRUE if successful, FALSE otherwise.
  680.  */
  681.  
  682. BOOL CPage::TenantClip(BOOL fCut)
  683.     {
  684.     LPDATAOBJECT    pIDataObject;
  685.  
  686.     if (NULL==m_pTenantCur)
  687.         return FALSE;
  688.  
  689.     /*
  690.      * To perform a data transfer operation, we need to create a
  691.      * data object with the selected object's data inside. To do
  692.      * this we CoCreateInstance on CLSID_DataTransferObject
  693.      * (Also implemented in this chapter), retrieve data from the
  694.      * object we have, stuff that data into the transfer object,
  695.      * then stick that object on the clipboard.
  696.      *
  697.      * Since we'll want an identical object at other times, like
  698.      * for drag-drop, we use a private function to actually create it.
  699.      */
  700.  
  701.     pIDataObject=TransferObjectCreate(NULL);
  702.  
  703.     if (NULL!=pIDataObject)
  704.         {
  705.         if (SUCCEEDED(OleSetClipboard(pIDataObject)))
  706.             {
  707.             if (fCut)
  708.                 TenantDestroy();
  709.  
  710.             return TRUE;
  711.             }
  712.  
  713.         pIDataObject->Release();
  714.         }
  715.  
  716.     return FALSE;
  717.     }
  718.  
  719.  
  720.  
  721.  
  722.  
  723. /*
  724.  * CPage::FQueryObjectSelected
  725.  *
  726.  * Purpose:
  727.  *  Returns whether or not there is an object selected on this
  728.  *  page for Cut, Copy, Delete functions.
  729.  *
  730.  * Parameters:
  731.  *  hMenu           HMENU of the Edit menu.
  732.  *
  733.  * Return Value:
  734.  *  BOOL            TRUE if we have an object, FALSE otherwise.
  735.  */
  736.  
  737. BOOL CPage::FQueryObjectSelected(HMENU hMenu)
  738.     {
  739.     return (NULL!=m_pTenantCur);
  740.     }
  741.  
  742.  
  743.  
  744.  
  745.  
  746.  
  747. /*
  748.  * CPages::FTenantGet
  749.  * (Protected)
  750.  *
  751.  * Purpose:
  752.  *  Returns a tenant of a given index returning a BOOL so it's simple
  753.  *  to use this function inside if statements.
  754.  *
  755.  * Parameters:
  756.  *  iTenant         UINT tenant to retrieve 0 based.
  757.  *  ppTenant        LPPAGE FAR * in which to return the tenant pointer
  758.  *  fOpen           BOOL indicating if we should open this tenant as well.
  759.  *
  760.  * Return Value:
  761.  *  BOOL            TRUE if successful, FALSE otherwise.
  762.  */
  763.  
  764. BOOL CPage::FTenantGet(UINT iTenant, LPTENANT FAR *ppTenant, BOOL fOpen)
  765.     {
  766.     if (NULL==ppTenant)
  767.         return FALSE;
  768.  
  769.     if (sizeof(LPTENANT)==SendMessage(m_hWndTenantList, LB_GETTEXT, iTenant
  770.         , (LONG)(LPVOID)ppTenant))
  771.         {
  772.         if (fOpen)
  773.             (*ppTenant)->FOpen(m_pIStorage);
  774.  
  775.         return TRUE;
  776.         }
  777.  
  778.     return FALSE;
  779.     }
  780.  
  781.  
  782.  
  783.  
  784.  
  785.  
  786.  
  787. /*
  788.  * CPage::FTenantAdd
  789.  * (Protected)
  790.  *
  791.  * Purpose:
  792.  *  Creates a new tenant initialized to the given values.  The new tenants's
  793.  *  storage is created if it does not already exist.  If fOpenStorage
  794.  *  is set the the tenants's storage is opened and left opened.
  795.  *
  796.  * Parameters:
  797.  *  iTenant         UINT Location at which to insert tenant; new tenant is
  798.  *                  inserted after this position.  0xFFFF for the end.
  799.  *  dwID            DWORD ID for this tenant.
  800.  *  ppNew           LPTENANT FAR * in which to store the new tenant.
  801.  *
  802.  * Return Value:
  803.  *  BOOL            TRUE if the function succeeded, FALSE otherwise.
  804.  */
  805.  
  806. BOOL CPage::FTenantAdd(UINT iTenant, DWORD dwID, LPTENANT FAR *ppNew)
  807.     {
  808.     LPTENANT    pTenant;
  809.     LRESULT     lr;
  810.  
  811.     if (NULL!=ppNew)
  812.         *ppNew=NULL;
  813.  
  814.     pTenant=new CTenant(dwID, m_hWnd, m_pPG);
  815.  
  816.     if (NULL==pTenant)
  817.         return FALSE;
  818.  
  819.     //Now try to add to the listbox.
  820.     lr=SendMessage(m_hWndTenantList, LB_INSERTSTRING, iTenant, (LONG)pTenant);
  821.  
  822.     if (lr < 0)
  823.         {
  824.         delete pTenant;
  825.         return FALSE;
  826.         }
  827.  
  828.     *ppNew=pTenant;
  829.     return TRUE;
  830.     }
  831.  
  832.  
  833.  
  834.  
  835.  
  836. /*
  837.  * CPage::TransferObjectCreate
  838.  * (Protected)
  839.  *
  840.  * Purpose:
  841.  *  Creates a DataTransferObject and stuff the current selection's
  842.  *  data into it.
  843.  *
  844.  * Parameters:
  845.  *  pptl            LPPOINTL containing the pick point in device units
  846.  *                  applicable only to drag-drop; since drag-drop is
  847.  *                  inherently mouse oriented, we use device units for
  848.  *                  the point.  Ignored if NULL.
  849.  *
  850.  * Return Value:
  851.  *  LPDATAOBJECT    Pointer to the object created, NULL on failure
  852.  */
  853.  
  854. LPDATAOBJECT CPage::TransferObjectCreate(LPPOINTL pptl)
  855.     {
  856.     LPDATAOBJECT    pIDataObject;
  857.     LPDATAOBJECT    pIDataT;
  858.     LPPATRONOBJECT  ppo;
  859.     RECTL           rcl;
  860.     LPUNKNOWN       pObj;
  861.     FORMATETC       fe;
  862.     STGMEDIUM       stm;
  863.     HRESULT         hr;
  864.  
  865.     m_pTenantCur->ObjectGet(&pObj);
  866.  
  867.     hr=CoCreateInstance(CLSID_DataTransferObject, NULL, CLSCTX_INPROC_SERVER
  868.         , IID_IDataObject, (LPVOID FAR *)&pIDataObject);
  869.  
  870.     if (FAILED(hr))
  871.         return NULL;
  872.  
  873.     //Go get the data we should hold on to.
  874.     hr=pObj->QueryInterface(IID_IDataObject, (LPVOID FAR *)&pIDataT);
  875.  
  876.     if (FAILED(hr))
  877.         {
  878.         pIDataObject->Release();
  879.         pObj->Release();
  880.         return NULL;
  881.         }
  882.  
  883.     //Copy from known object into transfer object.  Ordering is important!
  884.  
  885.     //Generate placeable object structure
  886.     stm.tymed=TYMED_HGLOBAL;
  887.     stm.pUnkForRelease=NULL;
  888.     stm.hGlobal=GlobalAlloc(GHND, sizeof(PATRONOBJECT));
  889.  
  890.     if (NULL==stm.hGlobal)
  891.         {
  892.         pIDataObject->Release();
  893.         pObj->Release();
  894.         return NULL;
  895.         }
  896.  
  897.     ppo=(LPPATRONOBJECT)GlobalLock(stm.hGlobal);
  898.  
  899.     m_pTenantCur->SizeGet(&ppo->szl, FALSE);
  900.     ppo->szl.cy=-ppo->szl.cy; //Negate to make absolute size
  901.  
  902.     m_pTenantCur->RectGet(&rcl, FALSE);
  903.     ppo->ptl.x=rcl.left;
  904.     ppo->ptl.y=rcl.top;
  905.  
  906.     if (NULL==pptl)
  907.         {
  908.         ppo->ptlPick.x=0;
  909.         ppo->ptlPick.y=0;
  910.         }
  911.     else
  912.         ppo->ptlPick=*pptl;
  913.  
  914.     m_pTenantCur->FormatEtcGet(&ppo->fe, FALSE);
  915.  
  916.     GlobalUnlock(stm.hGlobal);
  917.  
  918.     SETDefFormatEtc(fe, m_pPG->m_cf, TYMED_HGLOBAL);
  919.     pIDataObject->SetData(&fe, &stm, TRUE);
  920.  
  921.  
  922.     //Copy the actual presentation.
  923.     m_pTenantCur->FormatEtcGet(&fe, TRUE);
  924.     pIDataT->GetData(&fe, &stm);
  925.     pIDataObject->SetData(&fe, &stm, TRUE);
  926.  
  927.     pIDataT->Release();
  928.  
  929.     pObj->Release();
  930.     return pIDataObject;    //Caller now responsible
  931.     }
  932.  
  933.  
  934. //End CHAPTER7MOD
  935.